
// ----------------------------------------------------------------------------------
// Gramatica para reconocer codigo Flex
// ---------------------------------------------------------------------------------
grammar AnaFlex;

options {
  k = 2;
  language = Java;
}
tokens {
  
  INT = 'int';
  VOID = 'void';
  CHAR = 'char';
  RETURN = 'return';
  STRING = 'String';
}

@lexer::header {
  package PracticasPL.Practica5;
  import java.util.ArrayList;
}

@lexer::members {
      //Lista que guarda los errores que se van produciendo durante el analisis lexico
    List<RecognitionException> errors = new ArrayList<RecognitionException>();

    //Metodo que devuelve la lista de errores que se han producido
    public List<RecognitionException> getAllErrors() {
        return errors;
    }
    
    //Metodo que comprueba si se han producido errores
    public boolean hasErrors() {
        return !errors.isEmpty();
    }

    //Metodo del analizador lexico sobrescrito para que los errores que se van
    //produciendo durante el analisis lexico en vez de mostrarse por consola
    //se guarden en la lista de errores (errors)
    @Override
    public void reportError(RecognitionException e) {
        errors.add(e);
    }
}

@members {
      //Lista que guarda los errores que se van produciendo durante el analisis lexico
    List<RecognitionException> errors = new ArrayList<RecognitionException>();

    //Metodo que devuelve la lista de errores que se han producido
    public List<RecognitionException> getAllErrors() {
        return errors;
    }
    
    //Metodo que comprueba si se han producido errores
    public boolean hasErrors() {
        return !errors.isEmpty();
    }

    //Metodo del analizador lexico sobrescrito para que los errores que se van
    //produciendo durante el analisis lexico en vez de mostrarse por consola
    //se guarden en la lista de errores (errors)
    @Override
    public void reportError(RecognitionException e) {
        errors.add(e);
    }
}
@header {
  package PracticasPL.Practica5;
  import java.util.ArrayList;
}

// -----------------------------------------------------------------------
// Analizador lexico
// ------------------------------------------------------------------------

fragment NUEVA_LINEA: '\r'?'\n' ;

BLANCO: (' '|'\t'|NUEVA_LINEA)+ {$channel=HIDDEN;};

fragment DIGITO: '0'..'9';

NUMERO: (DIGITO)+('.'(DIGITO)+)?;
OPERADOR: '+'|'-'|'/'|'*';
PARENTESIS: '('|')';
SEPARADOR: ';';

protected LETRA: ('A'..'Z')|('a'..'z');
IDENT : (LETRA)((DIGITO)|(LETRA))*;

RANGO : '[' ((LETRA | DIGITO) '-' (LETRA | DIGITO))+ ']'; 

COMENTARIO: '/*' (options {greedy=false;}:.)* '*/' {$channel=HIDDEN;};


SEPARADOR_BLOQUES : '%%';
SEPARADOR_DEF_VAR : '%{' | '%}';

LLAVES : '{' | '}';

VAR_LEXICA : LLAVES IDENT LLAVES;

OR : '|';

COMA : ',';

ASIGNACION : '=';

//TIPO_STRING : 'String';
COMILLAS : '"';
DEF_FORMATO : '%' LETRA;
CADENA : COMILLAS (LETRA | NUMERO | ' '|'\\'| DEF_FORMATO | ASIGNACION)* COMILLAS;
VECTOR : IDENT '[' NUMERO? ']';


// -----------------------------------------------------------------------
// Analizador sintactico
// ------------------------------------------------------------------------
flex: bloq1 SEPARADOR_BLOQUES bloq2 SEPARADOR_BLOQUES bloq3;

bloq1: def_var_lex def_variable;

def_var_lex: (IDENT RANGO)+;
def_variable: SEPARADOR_DEF_VAR (tipo IDENT SEPARADOR)+ SEPARADOR_DEF_VAR; 

bloq2: reglas_lexicas;

reglas_lexicas : regla_1 regla_2;
regla_1 : (VAR_LEXICA (PARENTESIS VAR_LEXICA OR VAR_LEXICA PARENTESIS) OPERADOR (IDENT OPERADOR+) SEPARADOR) ;
regla_2 : (VAR_LEXICA OPERADOR (IDENT OPERADOR+) SEPARADOR) ;

bloq3: codigo_c;

codigo_c : def_funcion+;

def_funcion : retorno nombre PARENTESIS parametros PARENTESIS LLAVES cuerpo LLAVES;

retorno : INT;

nombre : IDENT;

cuerpo : (def_var_c  | llamada_funcion | return_statement  | variable)*;


def_var_c : IDENT ASIGNACION asignacion_var ;

variable : IDENT SEPARADOR;

asignacion_var : llamada_funcion | valor;

llamada_funcion : IDENT PARENTESIS parametros PARENTESIS SEPARADOR;

valor : NUMERO SEPARADOR;

parametros : VOID | ((tipo)? OPERADOR? (IDENT | VECTOR | CADENA) (COMA (tipo)? OPERADOR? (IDENT | VECTOR | CADENA))*)*;

tipo : INT | CHAR | STRING;

return_statement : RETURN NUMERO SEPARADOR;
